package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"unicode/utf8"

	"com.liu/im/producer"
	"github.com/sirupsen/logrus" // 导入 logrus 包
	"github.com/spf13/viper"
)

// 定义一个全局的idCounter变量，初始值为0
var idCounter int64

// 定义一个全局的连接映射
var connections = &sync.Map{}

// AddConnection 向连接映射中添加连接
func AddConnection(id int64, conn net.Conn) {
	connections.Store(id, conn)
}

// RemoveConnection 从连接映射中移除连接
func RemoveConnection(id int64) {
	connections.Delete(id)
}

// 连接激活时调用
func active(conn net.Conn) {
	// 原子操作增加idCounter的值，获取当前连接的唯一ID
	id := atomic.AddInt64(&idCounter, 1)
	// 为了修复 `logrus` 未定义的问题，需要导入 `logrus` 包

	// 后续代码保持不变
	logrus.Infof("客户端 (ID: %d) 已连接: %s", id, conn.RemoteAddr())
	// 将id和conn存入连接映射
	AddConnection(id, conn)
}

// 连接关闭时调用
func inactive(conn net.Conn) {
	// 遍历连接映射，找到对应的id并删除
	connections.Range(func(key, value interface{}) bool {
		if value.(net.Conn) == conn {
			RemoveConnection(key.(int64))
			return false
		}
		return true
	})
	logrus.Infof("客户端已断开连接: %s", conn.RemoteAddr())
}

// 处理客户端消息
func channelmessage(conn net.Conn, message string) {
	logrus.Infof("进入 channelmessage 函数，客户端地址: %s", conn.RemoteAddr())
	// 尝试将消息转为有效的UTF-8编码
	if !utf8.ValidString(message) {
		// 这里简单地将非UTF-8字符替换为U+FFFD（替换字符）
		validMessage := make([]rune, 0, len(message))
		for _, r := range message {
			if utf8.ValidRune(r) {
				validMessage = append(validMessage, r)
			} else {
				validMessage = append(validMessage, '\uFFFD')
			}
		}
		message = string(validMessage)
		logrus.Infof("收到的消息不是有效的UTF-8编码，已转换: %s", conn.RemoteAddr())
	}
	logrus.Infof("收到来自 %s 的消息: %s", conn.RemoteAddr(), message)
	// 回显消息给客户端，确保以UTF-8编码发送
	response := []byte("服务器已收到: " + message + "\n")
	if _, err := conn.Write(response); err != nil {
		logrus.Errorf("向客户端发送消息时出错: %v", err)
	}
	logrus.Infof("channelmessage 函数处理完成，客户端地址: %s", conn.RemoteAddr())

	// 假设SendMessage是一个独立函数，而不是producer的方法，直接调用该函数
	// 由于 producer.SendMessage 未定义，推测应调用前面定义的 SendMessage 函数
	// 由于im未定义，根据前面定义的SendMessage函数，修改为直接调用SendMessage函数
	_, nameServerAddrs, topic, _, groupName, _ := loadConfig()
	// 根据报错，此处应使用赋值运算符 `=` 而不是短变量声明 `:=`
	// 因为 `err` 已经在前面被声明过了
	sendErr := producer.SendMessage(nameServerAddrs, topic, message, groupName)
	if sendErr != nil {
		fmt.Printf("Error: %v\n", sendErr)
	}

}

// 处理新连接
func handleConnection(conn net.Conn) {
	defer func(conn net.Conn) {
		_ = conn.Close()
	}(conn)

	// 连接激活
	active(conn)

	// 读取客户端消息
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		message := scanner.Text()
		logrus.Infof("读取到客户端消息: %s", message)
		channelmessage(conn, message)
	}

	// 处理扫描错误
	if err := scanner.Err(); err != nil {
		logrus.Errorf("从客户端读取数据时出错: %v", err)
	}

	// 连接关闭
	inactive(conn)
}

// 加载配置文件
// 修改函数签名，使其返回所有需要的参数
func loadConfig() (string, string, string, int, string, error) {
	// 配置viper
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("..")

	// 读取配置文件
	if err := viper.ReadInConfig(); err != nil {
		var configFileNotFoundError viper.ConfigFileNotFoundError
		if errors.As(err, &configFileNotFoundError) {
			log.Printf("未找到配置文件，使用默认值: %v", err)
		}
	}

	// 从配置文件获取IP和端口
	host := viper.GetString("server.host")
	nameServerAddrs := viper.GetString("rocketmq.name_server")
	topic := viper.GetString("rocketmq.topic")
	port := viper.GetInt("server.port")
	groupName := viper.GetString("rocketmq.group_name")
	return host, nameServerAddrs, topic, port, groupName, nil
}

func main() {
	// 加载配置文件
	// 原代码中缺少逗号分隔 `group_name` 和 `err`，这里进行修正
	host, name_server_addrs, topic, port, group_name, err := loadConfig()
	logrus.Infof("name_server_addrs: %s", name_server_addrs)
	logrus.Infof("topic: %s", topic)
	logrus.Infof("group_name: %s", group_name)
	logrus.Infof("host: %s", host)
	logrus.Infof("port: %d", port)
	if err != nil {
		log.Fatalf("加载配置文件失败: %v", err)
	}

	address := fmt.Sprintf("%s:%d", host, port)

	// 监听端口
	listener, err := net.Listen("tcp", address)
	if err != nil {
		log.Fatalf("无法监听 %s: %v", address, err)
	}
	defer func(listener net.Listener) {
		_ = listener.Close()
	}(listener)

	log.Printf("服务器正在监听 %s", address)

	// 接受新连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Printf("接受连接时出错: %v", err)
			continue
		}
		// 为每个连接创建一个新的goroutine
		go handleConnection(conn)
	}
}
